#pragma once 

#include <iostream>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <sys/wait.h>
#define SIZE 1024

class Nocpy
{
public:
    ~Nocpy(){}
    Nocpy(){}
private:
    Nocpy(const Nocpy& n){}
    Nocpy& operator=(const Nocpy& n)
    {return *this;}
};

class Shell : public Nocpy
{
public:
    Shell(){}
    ~Shell(){}
    void Start() 
    {
        InitialEnv(); //初始化环境变量
        while(true)
        {
            GetCmd(); //获取提示符
            std::cout << _cmdline;
            fflush(stdout);
            std::string _cmdmess;
            getline(std::cin,_cmdmess);
            ParseCmd(_cmdmess);
            // for (int i = 0; i < argc; i++) std::cout << argv[i] << std::endl;
            if (argc > 0)
            {
                if (_IsInnerKey) //内建命令
                {
                    HandlerInner();
                }
                else  //普通命令
                {
                    Excute();
                }
            }
            argc = 0;
            _IsInnerKey = false;
        }
    }
private:
    std::string _cmdline = "";
    char* argv[SIZE];
    char* env[SIZE];
    int argc = 0;
    bool _IsInnerKey = false;
    void ParseCmd(std::string& message)
    {
        if (message.size() == 0) return;
        //"ls -a -b -c -d -f"
        size_t pos = 0;
        while(pos < message.size())
        {
            while(message[pos] == ' ' && pos < message.size()) pos++; //取出开头
            int p1 = message.find(" ",pos+1);
            if (pos >= message.size()) break;
            std::string tmp = message.substr(pos,p1-pos);
            if (tmp == "cd") _IsInnerKey = true;
            argv[argc] = (char*)malloc(tmp.size()+1);
            strcpy(argv[argc],tmp.c_str());
            argv[argc][tmp.size()] = 0;
            argc++;
            pos = p1;
        }
        argv[argc] = nullptr;
        _IsInnerKey = _IsInnerKey && (argc==2);
    }
    void InitialEnv()
    {
        extern char** environ;
        int i = 0;
        while(environ[i] != nullptr)
        {
            int len = strlen(environ[i]);
            env[i] = (char*)malloc(len+1);
            strcpy(env[i],environ[i]);
            env[i][len] = 0;
            i++;
        }
        env[i] = nullptr;
    }
    void Excute()
    {
        pid_t fd = fork();
        if (fd == 0) //子进程
        {
            int ret = ::execvpe(argv[0],argv,env);
            if (ret < 0) 
            {
                std::cout << "command not Found!!" << std::endl;
                exit(1);
            }
            exit(0);
        }
        //等待子进程
        pid_t wid = ::waitpid(fd,nullptr,0); //阻塞等待
        if (wid > 0)
        {
            // std::cout << "等待子进程成功" << std::endl;
        }

    }
    void HandlerInner()
    {
        if (argc == 2 && strcmp(argv[0],"cd") == 0)
        {
            int ret = chdir(argv[1]);
            if (ret < 0)
            {
                std::cout << "No such directory!!" << std::endl;
                return;
            }

        }
        else 
        {
            //
        }
    }
    void GetCmd()
    {
        std::string user = getenv("USER");
        std::string hostname = getenv("HOSTNAME") == nullptr ? "NONE" : getenv("HOSTNAME");
        char buffer[64];
        getcwd(buffer,sizeof(buffer));
        std::string cwd = buffer;
        std::string t = "/home/" + user;
        auto pos = cwd.find(t);
        if (pos >= 0 && pos < cwd.size()) //处理
        {
            //    /home/dpj/code
            std::string tmp = cwd.substr(pos+t.size()); //得到 /code
            cwd = "~" + tmp;
        }
        //dpj@iZ2zee7b26b1g3ujcquk70Z:~/linux_code/code/ShellBlog$
        _cmdline = user + "@" + hostname + ":" + cwd + "# "; //用"#"和"$"区分
    }    
};
